/** * */ package ecologylab.generic; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; /** * An attempt to make an object for storing other objects. If only one object * exists in the collection, then it is stored here, otherwise it's stored in a * hashmap where it can be randomly accessed. This is meant primarily for * applications where you're likely to have a LOT of single entires, but may * occasionally have a very large number (for example, in a hashmap that maps IP * address to connection). * * ObjectOrHashMap stores a single key value pair, until more than one such pair * has been specified, then it switches to using a HashMap instead of the pair. * To avoid constructing too many HashMaps, it never destroys the internal * HashMap once it has been created. It is assumed that ObjectOrHashMap will * generally be used in another Collection and when it is removed from that * Collection, it will be destroyed. * * @author Zachary O. Toups (zach@ecologylab.net) * */ public class ObjectOrHashMap<K, V> implements Map<K, V> { private class OOHMEntry implements Map.Entry<K, V> { private K key; private V value; private Map<K, V> parent; public OOHMEntry(K key, V value, Map<K, V> parent) { this.key = key; this.value = value; this.parent = parent; } /** * @see java.util.Map.Entry#getKey() */ @Override public K getKey() { return key; } /** * @see java.util.Map.Entry#getValue() */ @Override public V getValue() { return value; } /** * @see java.util.Map.Entry#setValue(java.lang.Object) */ @Override public V setValue(V value) { this.value = value; return this.parent.put(key, value); } } private K singleKey; private V singleValue; HashMap<K, V> mappings; public ObjectOrHashMap() { } public ObjectOrHashMap(K key, V value) { this.singleKey = key; this.singleValue = value; } private HashMap<K, V> mappings() { HashMap<K, V> currentMap = mappings; if (currentMap == null) { currentMap = new HashMap<K, V>(); mappings = currentMap; } return currentMap; } /** * @see java.util.Map#clear() */ @Override public void clear() { singleKey = null; singleValue = null; if (mappings != null) mappings.clear(); } /** * @see java.util.Map#containsKey(java.lang.Object) */ @Override public boolean containsKey(Object key) { return singleKey == null ? mappings().containsKey(key) : singleKey .equals(key); } /** * @see java.util.Map#containsValue(java.lang.Object) */ @Override public boolean containsValue(Object value) { return singleValue == null ? mappings().containsValue(value) : singleValue.equals(value); } /** * @see java.util.Map#entrySet() */ @Override public Set<java.util.Map.Entry<K, V>> entrySet() { if (singleValue != null) { // just one; we need to make the set Set<Map.Entry<K, V>> set = new LinkedHashSet<Map.Entry<K, V>>(1); set.add(new OOHMEntry(singleKey, singleValue, this)); return set; } else { return mappings().entrySet(); } } /** * @see java.util.Map#get(java.lang.Object) */ @Override public V get(Object key) { return singleValue == null ? mappings().get(key) : singleValue; } /** * @see java.util.Map#isEmpty() */ @Override public boolean isEmpty() { // check single value, then mappings, then if mappings exist, we check // its emptiness return singleValue == null || mappings == null || mappings.isEmpty(); } /** * @see java.util.Map#keySet() */ @Override public Set<K> keySet() { if (singleKey == null) { return mappings().keySet(); } else { Set<K> set = new LinkedHashSet<K>(1); set.add(singleKey); return set; } } /** * @see java.util.Map#put(java.lang.Object, java.lang.Object) */ @Override public V put(K key, V value) { if (singleKey != null) { mappings().put(singleKey, singleValue); this.singleKey = null; this.singleValue = null; } // we already know it's instantiated b/c we just did it return mappings.put(key, value); } /** * @see java.util.Map#putAll(java.util.Map) */ @Override public void putAll(Map<? extends K, ? extends V> t) { if (singleKey != null) { mappings().put(singleKey, singleValue); } mappings.putAll(t); } /** * @see java.util.Map#remove(java.lang.Object) */ @Override public V remove(Object key) { if (singleKey != null && singleKey.equals(key)) { singleKey = null; V retVal = singleValue; singleValue = null; return retVal; } else if (mappings != null) { return mappings.remove(key); } else { return null; } } /** * @see java.util.Map#size() */ @Override public int size() { return singleKey == null ? (mappings == null ? 0 : mappings.size()) : 1; } /** * @see java.util.Map#values() */ @Override public Collection<V> values() { System.out.println("getting values."); if (mappings != null) { // System.out.println("mappings are not null."); return mappings.values(); } else { // System.out.println("mappings are null."); Collection<V> coll = new LinkedHashSet<V>(1); if (singleValue != null) coll.add(singleValue); return coll; } } }